﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;

namespace System.Web.Mvc.Html
{
    public static class HtmlHelpers
    {
        public static MvcHtmlString DisplayRowFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
		{
            return HtmlHelpers.DisplayRowFor(html, expression, null);
        }
        public static MvcHtmlString DisplayRowFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string displayTemplate)
        {
            var sb = new StringBuilder();
            sb.Append("<tr><td class=\"editor-label\">");
            sb.Append(html.LabelFor(expression).ToHtmlString());
            sb.Append("</td><td class=\"editor-field\">");
            sb.Append(html.DisplayFor(expression, displayTemplate).ToHtmlString());
            sb.Append("</td></tr>");
            return MvcHtmlString.Create(sb.ToString());
        }

        public static MvcHtmlString EditorRowFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            return HtmlHelpers.EditorRowFor(html, expression,  html.EditorFor(expression));
        }
        public static MvcHtmlString EditorRowFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string editorTemplate)
        {
            return HtmlHelpers.EditorRowFor(html, expression, html.EditorFor(expression, editorTemplate));
        }
        public static MvcHtmlString EditorRowFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, MvcHtmlString editor)
        {
            var sb = new StringBuilder();
            sb.Append("<tr><td class=\"editor-label\">");
            sb.Append(html.LabelFor(expression).ToHtmlString());
            sb.Append("</td><td class=\"editor-field\">");
            sb.Append(editor.ToHtmlString());
            sb.Append(html.ValidationMessageFor(expression).ToHtmlString());
            sb.Append("</td></tr>");
            return MvcHtmlString.Create(sb.ToString());
        }

        public static IEnumerable<TModel> Sort<TModel>(this HtmlHelper<IEnumerable<TModel>> html, IEnumerable<TModel> model)
        {
            var queryValues = html.ViewContext.RequestContext.HttpContext.Request.QueryString;
            string propertyName = queryValues["sort"];
            if (string.IsNullOrEmpty(propertyName))
                return model;
            var type = typeof(TModel);
            var property = typeof(TModel).GetProperty(propertyName);
            if (property == null)
                return model;
            if (queryValues["sortdir"] == "DESC")
                return model.OrderByDescending(item => property.GetValue(item));
            else
                return model.OrderBy(item => property.GetValue(item));
        }

        public static MvcHtmlString ColumnHeaderFor<TModel, TValue>(this HtmlHelper<IEnumerable<TModel>> html, Expression<Func<TModel, TValue>> expression, bool allowSort = true)
        {
            var sb = new StringBuilder();
            sb.Append("<th>");
            MvcHtmlString displayName = html.DisplayNameFor(expression);
            if (allowSort)
            {
                var metadata = ModelMetadata.FromLambdaExpression(expression, new ViewDataDictionary<TModel>());
                string property = metadata.PropertyName;
                sb.Append(GetSortUrl(html, property, displayName).ToString());
            }
            else
            {
                sb.Append(displayName.ToString());
            }
            sb.Append("</th>");

            return MvcHtmlString.Create(sb.ToString());
        }

        private static MvcHtmlString GetSortUrl(HtmlHelper htmlHelper, string property, MvcHtmlString displayName)
        {
            string style = string.Empty;

            // create route valeus
            var queryValues = htmlHelper.ViewContext.RequestContext.HttpContext.Request.QueryString;
            var routeValues = new Routing.RouteValueDictionary(htmlHelper.ViewContext.RequestContext.RouteData.Values);
            for (int i = 0; i < queryValues.Count; i++)
                routeValues[queryValues.GetKey(i)] = queryValues[i];

            // update sort parameters
            routeValues["sort"] = property;
            routeValues["sortdir"] = "ASC";
            if (queryValues["sort"] == property)
            {
                if (queryValues["sortdir"] == "ASC")
                {
                    routeValues["sortdir"] = "DESC";
                    style = "sort-asc";
                }
                if (queryValues["sortdir"] == "DESC")
                {
                    style = "sort-desc";
                }
            }

            MvcHtmlString link = htmlHelper.RouteLink(displayName.ToString(), routeValues);
            if (string.IsNullOrEmpty(style))
            {
                return htmlHelper.RouteLink(displayName.ToString(), routeValues);
            }
            else
            {
                return htmlHelper.RouteLink(displayName.ToString(), routeValues, new Dictionary<string, object> { { "class", style } });
            }
        }
    }
}